home *** CD-ROM | disk | FTP | other *** search
- Issue #021
- March, 1997
-
-
- Contents:
-
- Pointers to Members
- A New Angle on Function Pointers
- Notes From ANSI/ISO - Clarifications on Exception Handling
- Introduction to STL Part 8 - advance() and distance()
-
-
- POINTERS TO MEMBERS
-
- In ANSI C, function pointers are used like this:
-
- #include <stdio.h>
-
- void f(int i)
- {
- printf("%d\n", i);
- }
-
- typedef void (*fp)(int);
-
- void main()
- {
- fp p = &f;
-
- (*p)(37); /* these are equivalent */
-
- p(37);
- }
-
- and are employed in a variety of ways, for example to specify a
- comparison function to a library function like qsort().
-
- In C++, pointers can be similarly used, but there are a couple of
- quirks to consider. We will discuss two of them in this section, and
- another one in the next section.
-
- The first point to mention is that C++ has C-style functions in it, but
- also has other types of functions, notably member functions. For
- example:
-
- class A {
- public:
- void f(int);
- };
-
- In this example, A::f(int) is a member function. That is, it
- operates on object instances of class A, and the function itself has
- a "this" pointer that points at the instance in question.
-
- Because C++ is a strongly typed language, it is desirable that a
- pointer to a member function be treated differently than a pointer to
- a C-style function, and that a pointer to a function member of class A
- be distinguished from a pointer to a member of class B. To do this,
- we can say:
-
- #include <iostream.h>
-
- class A {
- public:
- void f(int i) {cout << "value is: " << i << "\n";}
- };
-
- typedef void (A::*pmfA)(int);
-
- pmfA x = &A::f;
-
- void main()
- {
- A a;
- A* p = &a;
-
- (p->*x)(37);
- }
-
- Note the notation for actually calling the member function.
-
- It is not possible to intermix such a type with other pointer types,
- so for example:
-
- void f(int) {}
-
- pmfA x = &f;
-
- is invalid.
-
- A static member function, as in:
-
- class A {
- public:
- static void g(int);
- };
-
- typedef void (*fp)(int);
-
- fp p = &A::g;
-
- is treated like a C-style function. A static function has no "this"
- pointer and does not operate on actual object instances.
-
- Pointers to members are typically implemented just like C function
- pointers, but there is an issue with their implementation in cases
- where inheritance is used. In such a case, you have to worry about
- computing offsets of subobjects, and so on, when calling a member
- function, and for this purpose a runtime structure similar to a
- virtual table used for virtual functions is used.
-
- It's also possible to have pointers to data members of a class, with
- the pointer representing an offset into a class instance. For example:
-
- #include <iostream.h>
-
- class A {
- public:
- int x;
- };
-
- typedef int A::*piA;
- piA x = &A::x;
-
- void main()
- {
- A a;
- A* p = &a;
-
- a.x = 37;
-
- cout << "value is: " << p->*x << "\n";
- }
-
- Note that saying "&A::x" does not take the address of an actual data
- member in an instance of A, but rather computes a generic offset that
- can be applied to any instance.
-
-
- A NEW ANGLE ON FUNCTION POINTERS
-
- The discussion on function pointers in this issue overlooks one key
- angle that has fairly recently been introduced into the language.
- This involves distinguishing between C and C++ pointers. A C-style
- pointer in C++, that is, one that does not point to a member function,
- is used just like a function pointer in C. But according to the
- standard (section 7.5), such a pointer in fact has a different type.
-
- For example, consider:
-
- extern "C" typedef void (*fp1)(int);
-
- extern "C++" typedef void (*fp2)(int);
-
- extern "C" void f(int);
-
- fp1 and fp2 are not the same type, and saying:
-
- fp2 p = &f;
-
- to initialize p to the f(int) declared in the 'extern "C"' will not
- work.
-
- It is possible to overload functions on this basis, so that for
- example:
-
- extern "C" void f(void (*)(int));
-
- extern "C++" void f(void (*)(int));
-
- is legal, with the appropriate f() called based on the function
- pointer type passed to it. The function pointer parameter types in
- this example are not identical; the first is a pointer to a C
- function, the second a pointer to a C++ one.
-
- This feature is new and may not be implemented in your local C++
- compiler.
-
-
- NOTES FROM ANSI/ISO - CLARIFICATIONS ON EXCEPTION HANDLING
- Jonathan Schilling, jls@sco.com
-
- The ANSI/ISO C++ standards meeting earlier this month in Nashua, New
- Hampshire, produced some clarifications of exception handling
- semantics.
-
- One interesting case is this one, which was featured in the January
- 1997 issue of the magazine C++ Report:
-
- try {
- // exception prone code here, that may do a throw
- }
- catch (...) {
- // common error code here
-
- try {
- throw; // re-throw to more specific handler
- }
- catch (ExceptA&) {
- // handle ExceptA here
- }
- catch (ExceptB&) {
- // handle ExceptB here
- }
- catch (...) {
- // handle unknown exceptions here
- }
-
- throw;
- }
-
- The idea behind the code is to factor out common error handling logic
- into the first part of the catch handler (so as not to replicate it),
- rethrow the exception to get error handling specific to the exception
- in the individual inner handlers, and then finally to rethrow the
- exception again to let functions further up the call chain do their
- handling.
-
- The question is, does this code work as intended? The draft standard
- speaks of a throw creating a temporary object that is then deleted when
- the corresponding handler exits. Does this mean that when the inner
- handlers above exit, the rethrow will be of a nonexistent temporary
- object? The standard isn't really clear on this, and some existing
- compilers have been found to do the deletion at the inner handler,
- with the result that the program crashes.
-
- The answer is that this code should indeed work as intended, and that
- the existing compilers for which this does not work are wrong.
- (Fortunately SCO's new C++ compiler is one of the ones that is getting
- it right!).
-
- Furthermore, the committee stated that the value of the standard library
- function uncaught_exception() (see C++ Newsletter #019) changes (from
- false to true) at both of the rethrows, until such time as the rethrown
- exception is caught again.
-
- Another exception handling issue that was clarified is whether base
- class destructors are called when a derived class destructor throws an
- exception:
-
- class B {
- public:
- ~B() { ... }
- };
-
- class D : public B {
- public:
- ~D() { throw "error"; }
- };
-
- void f() {
- try {
- D d;
- }
- catch (...) { }
- }
-
- Does ~B() get called as well as ~D()? The answer is yes. This may
- seem almost obvious -- it is part of the general principle of C++
- that constructed subobjects always get destroyed if something goes
- wrong with the enclosing object -- but in fact there was some debate
- on this within the committee.
-
- Finally, one of the comments from the ANSI public review period
- concerned an area of exception handling that needed no clarification
- but is often misunderstood:
-
- try {
- throw 0;
- }
- catch (void *) {
- // does the exception get caught here?
- }
-
- The handler should not catch the exception, but apparently in some
- compilers it does. The draft standard is clear that throw and catch
- types either have to match exactly, or be related by inheritance, or
- be subject to a pointer-to-pointer standard conversion. Since 0 is
- not of a pointer type, the last requirement isn't met, and no handler
- is found. Similarly note that the whole range of other standard
- conversions do not apply, so that for example a handler of type long
- does not catch an exception of type int.
-
-
- INTRODUCTION TO STL PART 8 - ADVANCE() AND DISTANCE()
-
- In the last issue we started discussing iterators. They are used in
- the Standard Template Library to provide access to the contents of
- data structures, and to cycle across multiple data elements.
-
- We presented two examples of iterator usage, the first involving
- pointers, the second a higher-level construct. Both of these examples
- require some grasp of pointer arithmetic, a daunting subject. There's
- another way to write the example we presented before, using a couple
- of STL iterator functions:
-
- #include <algorithm>
- #include <iterator>
- #include <vector>
- #include <iostream>
-
- using namespace std;
-
- const int N = 100;
-
- void main()
- {
- vector<int> iv(N);
-
- iv[50] = 37;
- iv[52] = 47;
-
- vector<int>::iterator iter = find(iv.begin(), iv.end(), 37);
- if (iter == iv.end()) {
- cout << "not found\n";
- }
- else {
- int d = 0;
- distance(iv.begin(), iter, d);
- //cout << "found at " << iter - iv.begin() << "\n";
- cout << "found at " << d << "\n";
- }
-
- advance(iter, 2);
- cout << "value = " << *iter << "\n";
- }
-
- The function distance() computes the distance between two iterator
- values. In this example, we know that we're starting at "iv.begin()",
- the beginning of the integer vector. And we've found a match at
- "iter", and so we can use distance() to compute the distance between
- these, and display this result. Note that more recently distance()
- has been changed to work more like a regular function, with the
- beginning and ending arguments supplied and the difference returned as
- the result of the function:
-
- d = distance(iv.begin(), iter);
-
- A similar issue comes up with advancing an iterator. For example,
- it's possible to use "++" for this, but cumbersome when you wish to
- advance the iterator a large value. Instead of ++, advance() can be
- used to advance the iterator a specified number of positions. In the
- example above, we move the iterator forward 2 positions, and then
- display the value stored in the vector at that location.
-
- These functions provide an alternative way of manipulating iterators,
- that does not depend so much on pointer arithmetic.
-
-
- ACKNOWLEDGEMENTS
-
- Thanks to Nathan Myers, Eric Nagler, David Nelson, and Jonathan
- Schilling for help with proofreading.
-
-
- SUBSCRIPTION INFORMATION / BACK ISSUES
-
- To subscribe to the newsletter, send mail to majordomo@world.std.com
- with this line as its message body:
-
- subscribe c_plus_plus
-
- Back issues are available via FTP from:
-
- rmi.net /pub2/glenm/newslett
-
- or on the Web at:
-
- http://rainbow.rmi.net/~glenm
-
- There is also a Java newsletter. To subscribe to it, say:
-
- subscribe java_letter
-
- using the same majordomo@world.std.com address.
-
- -------------------------
-
- Copyright (c) 1997 Glen McCluskey. All Rights Reserved.
-
- This newsletter may be further distributed provided that it is copied
- in its entirety, including the newsletter number at the top and the
- copyright and contact information at the bottom.
-
- Glen McCluskey & Associates
- Professional C++ Consulting
- Internet: glenm@glenmccl.com
- Phone: (800) 722-1613 or (970) 490-2462
- Fax: (970) 490-2463
- FTP: rmi.net /pub2/glenm/newslett (for back issues)
- Web: http://rainbow.rmi.net/~glenm
-